package com.ddwl.common.exception;

import com.alibaba.fastjson.JSONException;
import com.ddwl.schema.vo.base.RestVo;
import feign.codec.DecodeException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

/**
 * 异常全局处理
 *
 * @author Fu Zhaohui
 * @date 2016/1/14 0014
 */
@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
public class ExceptionHandlerAdvice {

    private final HttpServletRequest request;

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo serverException(Exception e) {
        log.error("系统异常:  {}", e.getMessage(), e);
        return RestVo.error("系统繁忙，请稍后重试〜");
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ResponseBody
    public RestVo requestHandlingNoHandlerFound() {
        return RestVo.notFound("服务未发现");
    }

    @ExceptionHandler(value = AuthException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo authResponse(AuthException ae) {
        return RestVo.forbid(ae.getMessage());
    }

    @ExceptionHandler(value = JSONException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo jsonResponse(JSONException je) {
        log.error("数据格式异常:   {}", je.getMessage(), je);
        return RestVo.valid("数据格式异常");
    }

    @ExceptionHandler(value = HttpMessageNotWritableException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo notWritableResponse(HttpMessageNotWritableException we) {
        log.error("HttpMessage异常:   {}", we.getMessage(), we);
        return RestVo.valid("HttpMessage异常");
    }

    @ExceptionHandler(value = HttpMediaTypeNotAcceptableException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo mediaTypeResponse(HttpMediaTypeNotAcceptableException e) {
        return RestVo.valid(e.getMessage());
    }

    @ExceptionHandler(value = DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo mediaTypeResponse(DuplicateKeyException dke) {
        log.error("数据重复：  {}", dke.getMessage(), dke);
        return RestVo.valid("数据已存在");
    }


    @ExceptionHandler(value = GlobalException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo globalResponse(GlobalException dke) {
        log.error("{} GlobalException:  {}", request != null ? request.getRequestURI() : null, dke.getMessage(), dke);
        return RestVo.error(dke.getCode(), dke.getMessage());
    }

    @ExceptionHandler(value = CommonException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo commonResponse(CommonException ce) {
        log.error("{} 数据异常： {}", request != null ? request.getRequestURI() : null, ce.getMessage(), ce);
        return RestVo.valid(ce.getMessage());
    }

    @ExceptionHandler(value = ParseException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo parseResponse(ParseException pe) {
        return RestVo.valid("日期格式错误 " + pe.getMessage());
    }

    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo supportResponse(HttpRequestMethodNotSupportedException e) {
        return RestVo.valid(e.getMessage());
    }

    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo mediaTypeResponse(HttpMediaTypeNotSupportedException e) {
        return RestVo.valid(e.getMessage());
    }

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo supportResponse(HttpMessageNotReadableException e) {
        return RestVo.valid(e.getMessage());
    }

    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo supportResponse(MissingServletRequestParameterException e) {
        return RestVo.valid(e.getMessage());
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo supportResponse(MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        String message = allErrors.stream().map(s -> s.getDefaultMessage()).collect(Collectors.joining(";"));
        return RestVo.valid(message);
    }

    @ExceptionHandler(value = PayException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo payResponse(PayException e) {
        log.error("支付异常:  {}", e.getMessage(), e);
        return RestVo.payFail(e.getMessage());
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo numberException(NumberFormatException ne) {
        log.error("数据类型异常", ne);
        return RestVo.valid("数据类型异常");
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo patternException(PatternSyntaxException pe) {
        log.error("参数异常", pe);
        return RestVo.valid("参数异常");
    }


    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo argsException(MethodArgumentTypeMismatchException ae) {
        log.error("参数类型异常", ae);
        return RestVo.valid("参数类型异常");
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo handle(ConstraintViolationException ce) {
        Set<ConstraintViolation<?>> violations = ce.getConstraintViolations();
        StringBuilder message = new StringBuilder();
        for (Iterator<ConstraintViolation<?>> iterator = violations.iterator(); iterator.hasNext(); ) {
            ConstraintViolation violation = iterator.next();
            message.append(violation.getMessage());
        }
        return RestVo.valid(message.toString());
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestVo handle(DecodeException e) {
        log.error("解码消息异常:  {}", e.getMessage(), e);
        return RestVo.error(e.getMessage());
    }

}
